'''
Created on 29-Jun-09

@author: jm
'''
from model.Session import __CURRENT_SESSION__, Session
__PROJECT_NAME__="wofm"

if __name__ == "__main__":
    # TODO: import localApp
    import sys,os

    if sys.platform == "win32":
        sys.path.insert(0, "c:\\software\\gapp123")
        sys.path.insert(0, "c:\\software\\gapp123\\google")
        sys.path.insert(0, "c:\\software\\gapp123\\lib\\django")
        sys.path.insert(0, "c:\\software\\gapp123\\lib\\webob")
        sys.path.insert(0, "c:\\software\\gapp123\\lib\\yaml\\lib")
    else:
        sys.path.insert(0, "/home/software/pygapp/")
        sys.path.insert(0, "/home/software/pygapp/google/")
        sys.path.insert(0, "/home/software/pygapp/google/appengine/")
        sys.path.insert(0, "/home/software/pygapp/lib/django/")
        sys.path.insert(0, "/home/software/pygapp/lib/webob/")
        sys.path.insert(0, "/home/software/pygapp/lib/yaml/lib/")
        sys.path.insert(0, "..")

  
try:
    from google.appengine.ext import db
    from google.appengine.api import users
except:
    print "No google appengine available"

from django.utils import simplejson as json

from server.Utils import *

"""
 * A Bank of items.
 *
 * A QuizBank is a collection of questions (or QuizItem), each of them with an unique ID.
 * A QuizBank has an ID, author(s), Date, and version. The ID is the same whatever the version.
 * Each question is followed by several answers, the correct answer, and other optional lines.
 * Each text can be in several languages.
 * A Question begins by \@LA where LA is the language (EN, FR, ES, DE,...), followed by an ID and the text
 * Answers follow directly the question and begin with an ID (number or letter followed by dot : 1. a. A.)
 * The next line following answers contains R=ID where ID indicates the correct answer (ie: R=2.)

    * DATETIME(year, month, day, hour, minute, second)
    * DATETIME('YYYY-MM-DD HH:MM:SS')
    * DATE(year, month, day)
    * DATE('YYYY-MM-DD')
    * TIME(hour, minute, second)
    * TIME('HH:MM:SS')

"""
#EXPIRATION_TIME = datetime.timedelta(seconds=60)
#return datetime.datetime.now() - EXPIRATION_TIME



class JsonModel(db.Model):
    ''' to be inherited to allow json serialization'''
    json=db.TextProperty() # json representation
    pickle=db.BlobProperty() # pickle representation

    def to_json(self):
        data = {}
        for prop in self.properties().values():
            data[prop.name] = prop.get_value_for_datastore(self)
        return json.dumps(data) 

    def updateFromDict(self,d):
        '''
        '''
        for prop in self.properties():
            if prop in d:
                try:
                    setattr(self, prop, d[prop])
                except Exception :
                    return (prop,str(Exception))
        self.put()
        return None
    
    ## Update an Entity from arguments (ws)
    #
    def updateFromArgs(self,**args):
        self.updateFromDict(args)

    def to_gwt(cls,package):
        clsName = cls.kind()
        s =["package "+package+".model;"]
        s.append("")
        #s.append("import com.google.gwt.core.client.GWT;")
        s.append("import com.google.gwt.core.client.JavaScriptObject;")
        s.append("import com.google.gwt.core.client.JsArray;")
        s.append("")
        s.append("public class "+clsName+" extends JavaScriptObject {")
        s.append("protected "+clsName+"() { }") 
        for prop in cls.properties().values():
            if prop.data_type == 'str':
                s.append( "public final native String get"+prop.name+"() /*-{ return this."+prop.name+"; }-*/;")
            elif prop.data_type == 'int':
                s.append( "public final native int get"+prop.name+"() /*-{ return this."+prop.name+"; }-*/;")
            elif prop.data_type == 'list':
                s.append( "public final native List get"+prop.name+"() /*-{ return this."+prop.name+"; }-*/;")
            else:
                s.append( "public final native String get"+prop.name+"() /*-{ return this."+prop.name+"; }-*/;")
        # TODO s .append( "public final String getStr() { return getName() + ' ' + getUrl() + ' ' + getPort()+ ' ' + getTimeUp(); } 
        s.append("")
        s.append("public static final native JsArray<"+clsName+"> get"+clsName+"s (String json) /*-{ return eval(json); }-*/;")
        s.append("")
        s.append("public static "+clsName+" get"+clsName+"(String result) { JsArray<"+clsName+"> sites = "+clsName+".get"+clsName+"s(result); return sites.get(0); }") 
        s.append("")
        s.append("}")

    #public final void listSites (JsArray<Site> cs){
    #    for (int i = 0, n = cs.length(); i < n; ++i) {
    #        GWT.log(cs.get(i).getStr(),null);
    #    }
    #}
        return s
    to_gwt = classmethod(to_gwt)

    def to_python(cls):
        clsName = cls.kind()
        s =[]
        s.append("class "+clsName+" (object):")
        s.append("    '''"+clsName+"'''") 
        s.append("    _ALL=[]")
        for prop in cls.properties().values():
            s.append( "    "+prop.name+" = None")
        s.append("")
        s.append("    def __init__(self):")
        s.append("        _ALL.append(self)")
        s.append("")
        for prop in cls.properties().values():
            s.append( "    def set"+prop.name+"(self, "+prop.name+"): self."+prop.name+"="+prop.name+"")
        s.append("")
        s.append("    def get"+clsName+"s (result):")
        s.append("        s="+clsName+"(result)") 
        s.append("        return s") 
        s.append("    get"+clsName+"s = staticmethod(get"+clsName+"s)")
        s.append("")
        s.append("    def get"+clsName+" (result):") 
        s.append("        s="+clsName+"(result)") 
        s.append("        return s") 
        s.append("    get"+clsName+" = staticmethod(get"+clsName+")")
        s.append("")

    def saveIt(self):
        '''save it in session: persistence'''
        __CURRENT_SESSION__.add( self.__name__, json.dumps(self) )
        
    #public final void listSites (JsArray<Site> cs){
    #    for (int i = 0, n = cs.length(); i < n; ++i) {
    #        GWT.log(cs.get(i).getStr(),null);
    #    }
    #}
        return __CURRENT_SESSION__ # or self
    to_python = classmethod(to_python)

class Locale(JsonModel):
    language=db.StringProperty(required=True)
    variant=db.StringProperty(default="")
    country=db.StringProperty(default="")

''' replaced by a string list of the form:
en: sdfds, fr: sadsa
'''
#class TranslatedText(JsonModel):
#    '''
#    local as a string instead reference to Locale
#    translated Text not stored in DB ? certainly cached. Versioning?
#    '''
#    lang = db.StringProperty(required=True)
#    text = db.StringProperty(required=True,multiline=True)

# verbose_name=None, name=None, default=None, required=False, validator=None, choices=None, indexed=True
class UserPrefs(JsonModel):
    user = db.StringProperty()  # User.user_id() (key???)
    autoUser = db.UserProperty(auto_current_user_add=True)
    creationTime = db.DateTimeProperty(auto_now_add=True)
    lastUpdate = db.DateTimeProperty(auto_now=True)
    lastConnexionTime = db.DateTimeProperty()
    timeElapsed= db.ListProperty(int)

    session = db.ReferenceProperty(Session) # None if not connected
    lastLink = db.LinkProperty()
    eMail = db.EmailProperty()
    im = db.IMProperty()
    phone = db.PhoneNumberProperty()
    address = db.PostalAddressProperty()
    language=db.StringProperty()
    #db.RatingProperty()

    facebook_account= db.StringProperty()
    twitter_account= db.StringProperty()
    userActif= db.BooleanProperty()
    dateUserClosed= db.StringProperty()
    auditTrail= db.StringProperty()
    
    defaultLanguage=db.StringProperty(default="en") # default for new
    lastLanguage= db.StringProperty()
    appreciation = db.RatingProperty()

    nbQuizzes= db.StringProperty()
    lastQuiz= db.StringProperty()

    currentQuizzes= db.StringListProperty() # All ongoing quizzes

    def get_creation_time(self):
        """ Returns the creation time, rendered as a string. We could do timezone
            math, but for now (because it's easy) we'll just emit a time delta
            (e.g. "15 minutes ago")
        """
        elapsed = time.time() - time.mktime(self.creationTime.timetuple())
        return relative_string(elapsed)

    def get_last_modified(self):
        """ Returns the last modification date as a reasonably formatted string """
        elapsed = time.time() - time.mktime(self.lastUpdate.timetuple())
        return relative_string(elapsed)

    def render(self,t=None):
        if t=="title": return self.__class__.__name__
        if t=="header": 
            return ["User","Creation Time","Last Update","Last Connexion","Session",
                    "Last Link","Alternate Email","IM","Phone","Address"]
        try: ref=self.session.ID
        except: ref=None
        return [str(self.user),
                str(self.creationTime),
                str(self.lastUpdate),
                str(self.lastConnexionTime),
                str(ref),
                str(self.lastLink),
                str(self.alternateEmail),
                str(self.im),
                str(self.phone),
                str(self.address)
              ]
            
    def __str__(self):
        return str([s for s in self.renderFunction()])

   
# for perfs reason; juts bind them: Q: code caching 
#Q1_UserPrefs = db.GqlQuery("SELECT __key__ FROM UserPrefs WHERE user = :1")
#Q2_UserPrefs = db.GqlQuery("SELECT * FROM UserPrefs WHERE user = :1")

def getGQLUserPrefs(user):
    query = UserPrefs.gql('WHERE user=:user')
    query.bind(user)
    return query.get()

def getUserPrefs(user):
    #q = db.GqlQuery("SELECT * FROM UserPrefs WHERE user = :1", user)
    return UserPrefs.filter("user=",user).get()

def getAllUsers():
    query = UserPrefs.all()
    return query.fetch(limit=5)

def getAllConnectedUsers():
    query = db.Query(UserPrefs)
    query.filter('session !=', '')
    query.order('-dateLastConnexion')
    return query.fetch(limit=100)


class Player(JsonModel):
    ID = db.StringProperty(required=True)
    name = db.StringProperty() 
    password = db.StringProperty() 
    games = db.StringListProperty()
    owner = db.UserProperty(auto_current_user_add=True)
    creationTime = db.DateTimeProperty(auto_now_add=True)
    lastUpdate = db.DateTimeProperty(auto_now=True)
    comment = db.StringProperty()
    
    def __str__(self):
        return self.ID+" "+str(self.owner)
    
## Game Room Where Player synchrinze before the game starts
#
class GameRoom(JsonModel):
    Name = db.StringProperty(required=True) # name on screen, ID
    owner = db.UserProperty(auto_current_user_add=True) # the guy who created it
    creationTime = db.DateTimeProperty(auto_now_add=True)
    lastUpdate = db.DateTimeProperty(auto_now=True)
    comment = db.StringProperty() # addition info on list
    nbSlots = db.IntegerProperty()
    gameKind = db.StringProperty()
    
    
class GameAlliances(JsonModel):
    ID = db.StringProperty(required=True)
    name = db.StringProperty() 
    players = db.StringListProperty()


class Game(JsonModel):
    ID = db.StringProperty(required=True)
    creationTime = db.DateTimeProperty(auto_now_add=True)
    lastUpdate = db.DateTimeProperty(auto_now=True)
    name = db.StringProperty() 
    mapID = db.StringProperty() 
    players = db.StringListProperty()
    started = db.BooleanProperty()
    actif = db.BooleanProperty()
    ended = db.BooleanProperty()
    nbSlots = db.IntegerProperty()  


class PlayerGame(JsonModel):
    IDgame = db.StringProperty(required=True)
    IDplayer = db.StringProperty(required=True) 
    ressources = db.StringListProperty()
    buildings = db.StringListProperty()
    units = db.StringListProperty()
    
    
class Map(JsonModel):
    ID = db.StringProperty(required=True)
    content = db.BlobProperty() 
    name = db.StringProperty() 


class MapCell(JsonModel):
    IDmap = db.StringProperty(required=True)
    X = db.IntegerProperty(required=True)
    Y = db.IntegerProperty(required=True)
    content = db.StringProperty() 
    resistance = db.IntegerProperty() 
    elevation = db.IntegerProperty() 
    vegetation = db.IntegerProperty() 
    wetness = db.IntegerProperty() 
    #building
    playerID = db.StringProperty()

class Unit(JsonModel):
    ID = db.StringProperty(required=True)
    type = db.StringProperty() 
    mapID = db.StringProperty() 
    positionX = db.IntegerProperty()
    positionY = db.IntegerProperty()
    skill = db.IntegerProperty()
    health = db.IntegerProperty()
    rest = db.IntegerProperty()
    inGameID = db.StringProperty()

class Ressource(JsonModel):
    ID = db.StringProperty(required=True)
    production = db.IntegerProperty()


class Building(JsonModel):
    ID = db.StringProperty(required=True)
    level = db.IntegerProperty()


def gapp_to_rpc (model,init=False):
    '''adapt to the local folder tree for RCP use by client'''
    import os
    pathGWT = os.path.join(os.path.dirname(__file__),  "..", "..", "src", "com", "avidys", __PROJECT_NAME__, "model")
    if os.path.exists(pathGWT):
        fileName = os.path.normpath(os.path.join(pathGWT , model.kind()+".java")) 
        writeFile (fileName, model.to_gwt("com.avidys."+__PROJECT_NAME__))
        print "wrote",fileName 
    else:
        print ("Path not found [" + pathGWT + "]")  

    fileName = "pythonClasses.py" 
    if init: 
        writeFile(fileName,["'''","pythonClasses automatically generated","'''"])
    appendFile (fileName, model.to_python())


def main():

    gapp_to_rpc (UserPrefs,init=True)
#    gapp_to_rpc (Session)
    gapp_to_rpc (Locale)
    #gapp_to_rpc (TranslatedText)
    #gapp_to_rpc (QuizBank)
    #gapp_to_rpc (QuizBankVersion)
    #gapp_to_rpc (QuizItem)
    #gapp_to_rpc (SessionQuizGiven)
    
    
if __name__ == "__main__":
    main()
